﻿using Opc.Ua;
using Opc.Ua.Client;
using Org.BouncyCastle.Asn1.Tsp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics.Tracing;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using thinger.CommunicationLib;
using thinger.CommunicationLibDemo;

namespace OPC_UA
{
    public partial class FrmMain : Form
    {
        public FrmMain()
        {
            InitializeComponent();
            this.lst_Info.Columns[1].Width = this.lst_Info.Width - this.lst_Info.Columns[0].Width - 30;
        }

        //创建通信对象
        private OPCUA device = new OPCUA();

        //创建连接正常标志位
        private bool isConnected = false;

        /// <summary>
        /// 选择的OPCUA变量的集合(读取多个变量)
        /// </summary>
        private List<Opc.Ua.NodeId> nodeIds = new List<Opc.Ua.NodeId>();

        private List<string> setVariables = new List<string>();
        private List<object> varTypes = new List<object>();

        #region 使用 private OPCUA device 建立连接及断开连接

        private async void btn_Connect_Click(object sender, EventArgs e)
        {
            if (!isConnected)
            {
                try
                {
                    await device.ConnectServer(this.txt_Url.Text);
                }
                catch (Exception ex)
                {
                    isConnected = false;
                    CommonMethods.AddLog(this.lst_Info, 0, "设备连接失败：" + ex.Message);
                    return;
                }

                isConnected = true;
                CommonMethods.AddLog(this.lst_Info, 0, "设备连接成功");
            }
            else
            {
                CommonMethods.AddLog(this.lst_Info, 0, "设备已连接!!");
            }
        }

        //断开连接

        private void btn_DisConn_Click(object sender, EventArgs e)
        {
            if (isConnected)
            {
                device?.Disconnect();
                CommonMethods.AddLog(this.lst_Info, 0, "设备断开连接");
                isConnected = false;
            }
            else
            {
                CommonMethods.AddLog(this.lst_Info, 0, "设备未连接!!");
            }
        }

        #endregion 使用 private OPCUA device 建立连接及断开连接

        #region 变量管理--把建立连接的OPCUA device 传进FrmOPCUAConfig窗体

        private void btn_VarManage_Click(object sender, EventArgs e)
        {
            if (CommonValidate())
            {
                //把建立连接的OPCUA device 传进FrmOPCUAConfig
                FrmOPCUAConfig frmOPCUAConfig = new FrmOPCUAConfig(device);

                DialogResult dialogResult = frmOPCUAConfig.ShowDialog();

                if (dialogResult == DialogResult.OK)
                {
                    //frmOPCDAConfig返回一个字典
                    Dictionary<string, object> list = frmOPCUAConfig.SelList;

                    if (list.Keys.Count > 0)
                    {
                        nodeIds.Clear();
                        //new之后清空
                        setVariables = new List<string>();//标签名
                        varTypes = new List<object>();//变量名

                        foreach (var item in list.Keys)
                        {
                            //把选择的变量放到nodeIds集合
                            nodeIds.Add(new Opc.Ua.NodeId(item));
                            setVariables.Add(item);
                            varTypes.Add(list[item]);
                        }
                        //combox绑定数据
                        this.cmb_VarType.DataSource = null;
                        this.cmb_VarType.DataSource = varTypes;
                        this.cmb_SetVariable.DataSource = null;
                        this.cmb_SetVariable.DataSource = setVariables;
                    }
                }
            }
            else
            {
                CommonMethods.AddLog(this.lst_Info, 1, "请检查是否连接");
            }
        }

        #endregion 变量管理--把建立连接的OPCUA device 传进FrmOPCUAConfig窗体

        //cmb_VarType和cmb_SetVariable相对应
        private void lst_Info_SelectedIndexChanged(object sender, EventArgs e)
        {
            //SelectedIndex是说被选中项的顺序(因为已经绑定了数组，所以可以)
            // 而SelectedItem是被选择项本身
            this.cmb_VarType.SelectedIndex = this.cmb_SetVariable.SelectedIndex;
        }

        #region 读取按钮，读取多个，根据nodeIds变量个数

        private void btn_Read_Click(object sender, EventArgs e)
        {
            if (CommonValidate())
            {
                try
                {
                    //读取方法(读取多个，根据nodeIds变量个数)
                    List<Opc.Ua.DataValue> result = device.ReadNodes(nodeIds.ToArray());
                    //解析数据
                    string data = string.Empty;

                    foreach (var item in result)
                    {
                        data += item.Value.ToString() + " ";
                    }
                    CommonMethods.AddLog(this.lst_Info, 0, "读取成功：" + data);
                }
                catch (Exception ex)
                {
                    CommonMethods.AddLog(this.lst_Info, 1, "读取失败：" + ex.Message);
                }
            }
            else
            {
                CommonMethods.AddLog(this.lst_Info, 1, "请检查是否连接");
            }
        }

        #endregion 读取按钮，读取多个，根据nodeIds变量个数

        #region 写入数据（根据cmb_VarType类型写入数据）

        private void btn_Write_Click(object sender, EventArgs e)
        {
            if (CommonValidate())
            {
                bool result = false;

                switch (this.cmb_VarType.Text.ToLower())
                {
                    case "boolean": result = device.WriteNode(this.cmb_SetVariable.Text, Convert.ToBoolean(this.txt_SetValue.Text)); break;
                    case "ushort": result = device.WriteNode(this.cmb_SetVariable.Text, Convert.ToUInt16(this.txt_SetValue.Text)); break;
                    case "short": result = device.WriteNode(this.cmb_SetVariable.Text, Convert.ToInt16(this.txt_SetValue.Text)); break;
                    case "uint": result = device.WriteNode(this.cmb_SetVariable.Text, Convert.ToUInt32(this.txt_SetValue.Text)); break;
                    case "int": result = device.WriteNode(this.cmb_SetVariable.Text, Convert.ToInt32(this.txt_SetValue.Text)); break;
                    case "float": result = device.WriteNode(this.cmb_SetVariable.Text, Convert.ToSingle(this.txt_SetValue.Text)); break;
                    case "double": result = device.WriteNode(this.cmb_SetVariable.Text, Convert.ToDouble(this.txt_SetValue.Text)); break;
                    case "string": result = device.WriteNode(this.cmb_SetVariable.Text, this.txt_SetValue.Text); break;
                    default:
                        break;
                }

                CommonMethods.AddLog(this.lst_Info, result ? 0 : 1, result ? "写入成功" : "写入失败");
            }
            else
            {
                CommonMethods.AddLog(this.lst_Info, 1, "请检查是否连接");
            }
        }

        #endregion 写入数据（根据cmb_VarType类型写入数据）

        /// <summary>
        /// 通用验证
        /// </summary>
        /// <returns></returns>
        private bool CommonValidate()
        {
            if (isConnected == false)
            {
                CommonMethods.AddLog(this.lst_Info, 1, "设备未连接，请检查");
                return false;
            }

            return true;
        }

        #region 订阅按钮（订阅主题，产生一个回调函数）

        private void btn_StartSubRead_Click(object sender, EventArgs e)
        {
            //参数：订阅主题，变量集合
            device.AddSubscription("subList", setVariables.ToArray(), ItemChangedNotificationCallback);
        }

        private void ItemChangedNotificationCallback(string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs eventArgs)
        {
            MonitoredItemNotification monitoredItemNotification = eventArgs.NotificationValue as MonitoredItemNotification;

            CommonMethods.AddLog(this.lst_Info, 0, "订阅读取成功：NodeId为：" + monitoredItem.ResolvedNodeId.ToString() + ";值为：" + monitoredItemNotification.Value.WrappedValue);
        }

        #endregion 订阅按钮（订阅主题，产生一个回调函数）

        //停止订阅
        private void btn_StopSubRead_Click(object sender, EventArgs e)
        {
            device.RemoveSubscription("subList");

            // device.RemoveAllSubscription();
        }
    }
}